#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2018 crane <crane@crane-pc>
#
# Distributed under terms of the MIT license.

from math import *

precision = 0.000000000001


'''
有时候牛顿迭代法可能也得不到好的结果
'''


def newton_method(x0, func, derived_func):
    '''
        x0: 初始root/zero 猜测
        func: 原函数
        derived_func: 导函数

        based on differential formular
        [ (x0-x1) * s0 = (f0-0) ]
    '''

    f0 = func(x0)               # function value of x0/ f(x0)
    s0 = derived_func(x0)       # slope of x0(derivative at x0)

    x1 = x0 - f0/s0

    print(x0, x1)
    if fabs(x0-x1) <= precision:
        return x1

    return newton_method(x1, func, derived_func)


def end_show(x0, f):
    f0 = f(x0)
    print('zeor test [%s] ------> test value [%s]\n' %(x0, f0))


def main():
    print("start main")

    # x^2 function's zero point
    # f = lambda x: x**2
    # x0 = newton_method(0.5, f, lambda x: 2*x)
    # f0 = f(x0)
    # print('zeor test [%s] ------> test value [%s]' %(x0, f0))


    '''
        x^5 + 2x - 1 = 0, 普林斯顿微积分读本 13.3
    '''
    f = lambda x: x**5 + 2*x - 1
    x0 = newton_method(0, f, lambda x: 5*x**4 + 2)
    end_show(x0, f)


    '''
        cos(x) - x = 0/x - cos(x) = 0
        普林斯顿微积分读本 13.3
        书中最后计算到: (1+pi/4) * (sqrt(2)-2)
    '''
    f = lambda x: x - cos(x)        # 因为导函数不带负号
    d = lambda x: 1 + sin(x)        # 导函数
    x0 = newton_method(0, f, d)
    end_show(x0, f)
    v=(1+pi/4) * (sqrt(2)-1)
    print(v)

if __name__ == "__main__":
    main()
